/**
 * 
 */
package com.vivid.dynamics.oknow.test.dao;

import java.io.Serializable;
import java.util.Date;

import org.junit.Assert;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.vivid.dynamics.junit.impl.SpringHibernateSupportJUnitTemplate;
import com.vivid.dynamics.oknow.dao.IPermissionDAO;
import com.vivid.dynamics.oknow.dao.IUserDAO;
import com.vivid.dynamics.oknow.model.Permission;
import com.vivid.dynamics.oknow.model.User;

/**
 *
 * @author jason
 * created at:: Aug 9, 2011 3:48:10 PM
 */
public class PermissionTestCase extends SpringHibernateSupportJUnitTemplate {
	/**
	 * IUserDAO, check the config under config/spring-config.xml
	 */
	private @Autowired IUserDAO userDAO;
	/**
	 * IPermissionDAO, check the config under config/spring-config.xml
	 */
	private @Autowired IPermissionDAO permissionDAO;
	
	/**
	 * ctor.
	 */
	public PermissionTestCase() {
		super(PermissionTestCase.class, true);
	}
	
	User userA=null;
	User userB=null;
	Serializable userAKey=null;
	Serializable userBKey=null;
	
	/**
	 * method(s) to create 2 default users for testing
	 * 
	 * @author jason
	 * created at:: Aug 9, 2011  12:06:58 PM
	 */
	protected void createDefaultUsers() {
		userA=new User("userA", "def", false, "hire", "a@abcAA.com", null);
		userB=new User("userB", "def", false, "hire", "a@abcBB.com", null);
		
		this.userAKey=this.userDAO.newUser(userA);
		this.userBKey=this.userDAO.newUser(userB);
	}
	
	/**
	 * <ul>
	 * 	<li>create 1 User(s) {userA}, and create some Permission entries for it {2 items}</li>
	 * 	<li>update the user's Permission</li>
	 * </ul>
	 * 
	 * @author jason
	 * created at:: Aug 9, 2011  3:50:27 PM
	 */
	@Test
	public void doTest001() {
		User aUsrA=null;
		Permission aPer01=null;
		Permission aPer02=null;
		Serializable aPer01Key=null;
		Serializable aPer02Key=null;
		
		this.sb.append("\r\n************************************************\r\n").
		    append("*\tstart {PermissionTestCase.doTest001}\t*\r\n").
			append("************************************************\r\n\r\n");
		try {
			this.createDefaultUsers();
			
			this.sb.append("1) create 1 User(s) {userA}, and create some Permission entries for it {2 items}:\r\n");
			aUsrA=this.userA;
			aPer01=new Permission("all:1", "all readable", "grant read rights to all...");
			aPer02=new Permission("grp-101:2", "group 101 can write", null);
			/*
			 * persist order
			 * a) owner --> User
			 * b) set associations between User and transient Permission
			 * c) persist Permission
			 */
			aUsrA.addPermission(aPer01);
			aUsrA.addPermission(aPer02);
			aPer01Key=this.permissionDAO.newPermission(aPer01);
			aPer02Key=this.permissionDAO.newPermission(aPer02);
			/*
			 * hashCode hell...
			 */
			this.sb.append("\r\nHashCode Hell~ the Set's hashCode() changed~therefore should never contains the previously added entities::\r\n\r\nUsrA has per01? ").append(aUsrA.getPermissions().contains(aPer01)).
				append("\r\nUsrA has per02? ").append(aUsrA.getPermissions().contains(aPer02)).append("\r\n");
			aUsrA.getPermissions().clear();
			aUsrA.addPermission(aPer01);
			aUsrA.addPermission(aPer02);
			this.userDAO.updateUser(aUsrA);
			
			// re-query
			aUsrA=this.userDAO.getUserByKey((Integer) this.userAKey);
			aPer01=this.permissionDAO.getPermissionByKey((Integer) aPer01Key);
			aPer02=this.permissionDAO.getPermissionByKey((Integer) aPer02Key);
			
			this.sb.append("\r\nHashCode Hell~ should be ok now, remove all, then re-add all, then update~\r\nUsrA has per01? ").append(aUsrA.getPermissions().contains(aPer01)).
				append("\r\nUsrA has per02? ").append(aUsrA.getPermissions().contains(aPer02)).append("\r\n\r\n");
			
			this.sb.append(aUsrA).append("\r\n\t\t");
			this.createToStringForCollections(this.sb, aUsrA.getPermissions());
			this.sb.append("\r\n\tPermissions:: \r\n\t\t").append(aPer01).append("\r\n\t\t").append(aPer01.getUser()).
				append("\r\n\t\t").append(aPer02).append("\r\n\t\t").append(aPer02.getUser()).append("\r\n\r\n");
			
			/*
			 * 2) update the user's Permission
			 */
			this.sb.append("2) update the user's Permission; prepend the timestamp for the description:\r\nsuccess? : true\r\n\r\n");
			if (aPer01!=null) {
				aPer01.setDescr(new Date()+" @@@ "+aPer01.getDescr());
				/*
				 * non n-to-n; either side can update
				 */
				//this.permissionDAO.updatePermission(aPer01);
				this.userDAO.updateUser(aUsrA);
			}
			// re-query
			aUsrA=this.userDAO.getUserByKey(aUsrA.getId());
			aPer01=this.permissionDAO.getPermissionByKey(aPer01.getId());
			aPer02=this.permissionDAO.getPermissionByKey(aPer02.getId());
			
			this.sb.append(aUsrA).append("\r\n\t\t");
			this.createToStringForCollections(this.sb, aUsrA.getPermissions());
			this.sb.append("\r\n\tPermissions:: \r\n\t\t").append(aPer01).append("\r\n\t\t").append(aPer01.getUser()).
				append("\r\n\t\t").append(aPer02).append("\r\n\t\t").append(aPer02.getUser()).append("\r\n\r\n");
			
			this.tx.flush();
			
		} catch (RuntimeException re) {
			this.sb.append("**************************************\r\n").
				append(re.toString()).
				append("\r\n**************************************\r\n");
			re.printStackTrace(System.out);
			throw re;
		}
	}
	
	/**
	 * Delete of permission from UserA
	 * 
	 * @author jason
	 * created at:: Aug 9, 2011  4:28:39 PM
	 */
	@Test
	public void doTest002() {
		User aUsrA=null;
		Permission aPer01=null;
		Permission aPer02=null;
		Serializable aPer01Key=null;
		Serializable aPer02Key=null;
		
		this.sb.append("\r\n************************************************\r\n").
		    append("*\tstart {PermissionTestCase.doTest002}\t*\r\n").
			append("************************************************\r\n\r\n");
		try {
			this.createDefaultUsers();
			
			aUsrA=this.userA;
			aPer01=new Permission("all:1", "all readable", "grant read rights to all...");
			aPer02=new Permission("grp-101:2", "group 101 can write", null);
			/*
			 * persist order
			 * a) owner --> User
			 * b) set associations between User and transient Permission
			 * c) persist Permission
			 */
			aUsrA.addPermission(aPer01);
			aUsrA.addPermission(aPer02);
			aPer01Key=this.permissionDAO.newPermission(aPer01);
			aPer02Key=this.permissionDAO.newPermission(aPer02);
			/*
			 * hashCode hell...
			 */
			this.sb.append("\r\nHashCode Hell~ the Set's hashCode() changed~therefore should never contains the previously added entities::\r\n\r\nUsrA has per01? ").append(aUsrA.getPermissions().contains(aPer01)).
				append("\r\nUsrA has per02? ").append(aUsrA.getPermissions().contains(aPer02)).append("\r\n");
			aUsrA.getPermissions().clear();
			aUsrA.addPermission(aPer01);
			aUsrA.addPermission(aPer02);
			this.userDAO.updateUser(aUsrA);
			
			// re-query
			aUsrA=this.userDAO.getUserByKey((Integer) this.userAKey);
			aPer01=this.permissionDAO.getPermissionByKey((Integer) aPer01Key);
			aPer02=this.permissionDAO.getPermissionByKey((Integer) aPer02Key);
			
			this.sb.append("\r\nHashCode Hell~ should be ok now, remove all, then re-add all, then update~\r\nUsrA has per01? ").append(aUsrA.getPermissions().contains(aPer01)).
				append("\r\nUsrA has per02? ").append(aUsrA.getPermissions().contains(aPer02)).append("\r\n\r\n");
			
			this.sb.append(aUsrA).append("\r\n\t\t");
			this.createToStringForCollections(this.sb, aUsrA.getPermissions());
			this.sb.append("\r\n\tPermissions:: \r\n\t\t").append(aPer01).append("\r\n\t\t").append(aPer01.getUser()).
				append("\r\n\t\t").append(aPer02).append("\r\n\t\t").append(aPer02.getUser()).append("\r\n\r\n");
			/*
			 * 3) Delete of permission from UserA 
			 */
			this.sb.append("3) Delete of permission from UserA, use ASSOCIATION method, remove permission002 ~\r\n\t\t");
			/*
			 * order
			 * a) association delete
			 * b) really DELETE the unwanted permission instance
			 * c) update either side~ however should update the Owner side... 
			 * 	since the other side might null already (logically)
			 */
			Assert.assertTrue("3) Per02 should NOT be null~", aPer02!=null);
			aUsrA.removePermission(aPer02);
			this.permissionDAO.deletePermission(aPer02);
			this.userDAO.updateUser(aUsrA);
			
			// re-query
			aUsrA=this.userDAO.getUserByKey(aUsrA.getId());
			aPer01=this.permissionDAO.getPermissionByKey(aPer01.getId());
			aPer02=this.permissionDAO.getPermissionByKey(aPer02.getId());
			
			this.sb.append(aUsrA).append("\r\n\t\t");
			this.createToStringForCollections(this.sb, aUsrA.getPermissions());
			this.sb.append("\r\n\tPermissions:: \r\n\t\t");
			if (aPer01!=null) this.sb.append("Per01::").append(aPer01).append("\r\n\t\t").append(aPer01.getUser()).append("\r\n\t\t");
			if (aPer02!=null) this.sb.append("Per02::").append(aPer02).append("\r\n\t\t").append(aPer02.getUser()).append("\r\n\r\n");
			
			this.tx.flush();
			
		} catch (RuntimeException re) {
			this.sb.append("**************************************\r\n").
				append(re.toString()).
				append("\r\n**************************************\r\n");
			re.printStackTrace(System.out);
			throw re;
		}
	}
	
	
	/**
	 * Test(s) on User and Permission associations
	 * <ul>
	 * 	<li>create 1 User(s) {userA}, and create some Permission entries for it {2 items}</li>
	 * 	<li>update the user's Permission</li>
	 * 	<li>Delete of permission from UserA</li>
	 * </ul>
	 * <b>PS</b>. bookmark n permission tests are performed in another JUnit method
	 * <p/>
	 * @author jason
	 * created at:: Aug 4, 2011  12:18:10 PM
	 * @deprecated
	 */
	//@Test
	public void doUserNPermissionTest001() {
		User aUsrA=null;
		Permission aPer01=null;
		Permission aPer02=null;
		Serializable aUsrKey=null;
		Serializable aPer01Key=null;
		Serializable aPer02Key=null;
		
		try {
			this.sb.append("\r\n************************************************\r\n").
			    append("*\tstart {doUserNPermissionTest001}\t*\r\n").
				append("************************************************\r\n\r\n");
			this.sb.append("1) create 1 User(s) {userA}, and create some Permission entries for it {2 items}:\r\n\tUser::\r\n\t\t");
			aUsrA=new User("usrA", "def", false, "h->a", "a@abcm.com", null);
			aPer01=new Permission("all:1", "all readable", "grant read rights to all...");
			aPer02=new Permission("grp-101:2", "group 101 can write", null);
			/*
			 * persist order
			 * a) owner --> User
			 * b) set associations between User and transient Permission
			 * c) persist Permission
			 */
			aUsrKey=this.userDAO.newUser(aUsrA);
			aUsrA.addPermission(aPer01);
			aUsrA.addPermission(aPer02);
			aPer01Key=this.permissionDAO.newPermission(aPer01);
			aPer02Key=this.permissionDAO.newPermission(aPer02);
			
			// re-query
			aUsrA=this.userDAO.getUserByKey((Integer) aUsrKey);
			aPer01=this.permissionDAO.getPermissionByKey((Integer) aPer01Key);
			aPer02=this.permissionDAO.getPermissionByKey((Integer) aPer02Key);
			
			this.sb.append(aUsrA).append("\r\n\t\t").append(aUsrA.getPermissions()).
				append("\r\n\tPermissions:: \r\n\t\t").append(aPer01).append("\r\n\t\t").append(aPer01.getUser()).
				append("\r\n\t\t").append(aPer02).append("\r\n\t\t").append(aPer02.getUser()).append("\r\n\r\n");
			
			/*
			 * 2) update the user's Permission
			 */
			this.sb.append("2) update the user's Permission; prepend the timestamp for the description:\r\nsuccess? : true\r\n\r\n");
			if (aPer01!=null) {
				aPer01.setDescr(new Date()+" @@@ "+aPer01.getDescr());
				/*
				 * update either side should be ok...
				 */
				this.permissionDAO.updatePermission(aPer01);
			}
			// re-query
			aUsrA=this.userDAO.getUserByKey(aUsrA.getId());
			aPer01=this.permissionDAO.getPermissionByKey(aPer01.getId());
			aPer02=this.permissionDAO.getPermissionByKey(aPer02.getId());
			
			this.sb.append(aUsrA).append("\r\n\t\t").append(aUsrA.getPermissions()).
				append("\r\n\tPermissions:: \r\n\t\t").append(aPer01).append("\r\n\t\t").append(aPer01.getUser()).
				append("\r\n\t\t").append(aPer02).append("\r\n\t\t").append(aPer02.getUser()).append("\r\n\r\n");
			
			/*
			 * 3) Delete of permission from UserA 
			 */
			this.sb.append("3) Delete of permission from UserA, use ASSOCIATION method, remove permission002 ~\r\n\t\t");
			/*
			 * order
			 * a) association delete
			 * b) really DELETE the unwanted permission instance
			 * c) update either side~ however should update the Owner side... 
			 * 	since the other side might null already (logically)
			 */
			aUsrA.removePermission(aPer02);
			this.permissionDAO.deletePermission(aPer02);
			this.userDAO.updateUser(aUsrA);
			
			// re-query
			aUsrA=this.userDAO.getUserByKey(aUsrA.getId());
			aPer01=this.permissionDAO.getPermissionByKey(aPer01.getId());
			aPer02=this.permissionDAO.getPermissionByKey(aPer02.getId());
			
			this.sb.append(aUsrA).append("\r\n\t\t").append(aUsrA.getPermissions()).
				append("\r\n\tPermissions:: \r\n\t\t");
			if (aPer01!=null) this.sb.append(aPer01).append("\r\n\t\t").append(aPer01.getUser()).append("\r\n\t\t");
			if (aPer02!=null) this.sb.append(aPer02).append("\r\n\t\t").append(aPer02.getUser()).append("\r\n\r\n");
			
			this.tx.flush();
			
		} catch (RuntimeException re) {
			this.sb.append("**************************************\r\n").
				append(re.toString()).
				append("\r\n**************************************\r\n");
			re.printStackTrace(System.out);
			throw re;
		}
	}
	
}
